#include "ShaderManager.h"

//Used to get the ID3D11Device*
#include "GraphicsManager.h"

//Include FX classes
#include "TexturedFullScreenQuadFX.h"
#include "DebugDrawLightsFX.h"
#include "SkyDomeFX.h"

#include "TileForwardNormalMapFX.h"
#include "TileForwardNormalMapInstFX.h"
#include "TileForwardStandardFX.h"
#include "TileForwardTextureMapFX.h"

#include "TileForwardTextureMapInstFX.h"
#include "TileForwardDisplacementMappingFX.h"
#include "TileForwardDisplacementMapInstFX.h"
#include "TileForwardSolidColourFX.h"
#include "TileForwardSolidColourInstFX.h"

#include "TileForwardAnimNormalMapFX.h"
#include "TileForwardAnimTextureMapFX.h"
#include "TileForwardAnimSolidColourFX.h"

#include "OceanWaveFX.h"
#include "TerrainFX.h"
#include "TerrainWaterFX.h"

#include "ParallaxOcclusionMappingFX.h"

//Roo's world specific
#include "ReflectRefractFX.h"

//Include CSFX
#include "TileForwardLightCullCSFX.h"

//Post proc / Screen space effects
#include "SSAOBlurFX.h"
#include "SSAOMapFX.h"
#include "SSAOBlurCSFX.h"

//Other
#include "SpriteFX.h"

//Init static pointer to 0
ShaderManager* ShaderManager::instance = 0;

ShaderManager::ShaderManager()
{
	//Simple message to tell us we are loading our shaders. 
	OutputDebugStringW(L"[Creating Shader Manager]\n");

	//Grab a pointer to the shared application
	ID3D11Device* device = GraphicsManager::GetInstance()->D3DDevice();

	//Init shaders.
	InitStandardEffects(device);
	InitCSEffects(device); 
}

ShaderManager::~ShaderManager()
{
	//Simple message to tell user we are deleting shaders. 
	OutputDebugStringW(L"[Releasing Shader Manager]\n");

	//SafeDelete all of our effects.
	SafeDelete(texturedFullScreenQuadFX);
	SafeDelete(debugDrawLightsFX);
	SafeDelete(skyDomeFX);

	SafeDelete(tileForwardNormalMapFX);
	SafeDelete(tileForwardNormalMapInstFX);
	SafeDelete(tileForwardStandardFX);
	SafeDelete(tileForwardTextureMapFX);
	SafeDelete(tileForwardTextureMapInstFX);

	SafeDelete(tileForwardDisplacementMappingFX);
	SafeDelete(tileForwardDisplacementMapInstFX);
	SafeDelete(tileForwardSolidColourFX);
	SafeDelete(tileForwardSolidColourInstFX);

	SafeDelete(tileForwardAnimNormalMapFX);
	SafeDelete(tileForwardAnimTextureMapFX);
	SafeDelete(tileForwardAnimSolidColourFX);

	SafeDelete(oceanWaveFX);
	SafeDelete(terrainFX);
	SafeDelete(terrainWaterFX);

	SafeDelete(pomFX);

	SafeDelete(reflectRefractFX);

	//Delete CSFX
	SafeDelete(tileForwardLightCullCSFX);

	//Delete Screen space / post proc effects
	SafeDelete(ssaoBlurFX);
	SafeDelete(ssaoMapFX);
	SafeDelete(ssaoBlurCSFX);

	//Delete other effects
	SafeDelete(spriteFX);
}

ShaderManager* ShaderManager::GetInstance()
{
	if (!instance)
		instance = new ShaderManager();

	return instance;
}

void ShaderManager::Release()
{
	if (instance)
	{
		delete instance;
		instance = 0;
	}
}

void ShaderManager::OnReallocOfLLB(ID3D11ShaderResourceView* llb)
{	
	//Update ALL TileForward Effects - update the Light List Buffer.
	tileForwardNormalMapFX->SetLightListBuffer(llb);
	tileForwardNormalMapInstFX->SetLightListBuffer(llb);
	tileForwardStandardFX->SetLightListBuffer(llb);
	tileForwardTextureMapFX->SetLightListBuffer(llb);
	tileForwardTextureMapInstFX->SetLightListBuffer(llb);
	tileForwardDisplacementMappingFX->SetLightListBuffer(llb);
	tileForwardDisplacementMapInstFX->SetLightListBuffer(llb);
	tileForwardSolidColourFX->SetLightListBuffer(llb);
	tileForwardSolidColourInstFX->SetLightListBuffer(llb);
	tileForwardAnimNormalMapFX->SetLightListBuffer(llb);
	tileForwardAnimTextureMapFX->SetLightListBuffer(llb);
	tileForwardAnimSolidColourFX->SetLightListBuffer(llb);

	oceanWaveFX->SetLightListBuffer(llb);
	terrainFX->SetLightListBuffer(llb);
	terrainWaterFX->SetLightListBuffer(llb);

	pomFX->SetLightListBuffer(llb);

	reflectRefractFX->SetLightListBuffer(llb);
}

void ShaderManager::OnResize(unsigned newWidth, unsigned newHeight)
{
	//Update ALL Tile Forward Effects with the new width and height of the
	//render target. Needed so we can work out what tile a fragment lies in.
	tileForwardNormalMapFX->SetRTDimensions(newWidth, newHeight);
	tileForwardNormalMapInstFX->SetRTDimensions(newWidth, newHeight);
	tileForwardStandardFX->SetRTDimensions(newWidth, newHeight);
	tileForwardTextureMapFX->SetRTDimensions(newWidth, newHeight);
	tileForwardTextureMapInstFX->SetRTDimensions(newWidth, newHeight);
	tileForwardDisplacementMappingFX->SetRTDimensions(newWidth, newHeight);
	tileForwardDisplacementMapInstFX->SetRTDimensions(newWidth, newHeight);
	tileForwardSolidColourFX->SetRTDimensions(newWidth, newHeight);
	tileForwardSolidColourInstFX->SetRTDimensions(newWidth, newHeight);
	tileForwardAnimNormalMapFX->SetRTDimensions(newWidth, newHeight);
	tileForwardAnimTextureMapFX->SetRTDimensions(newWidth, newHeight);
	tileForwardAnimSolidColourFX->SetRTDimensions(newWidth, newHeight);

	oceanWaveFX->SetRTDimensions(newWidth, newHeight);
	terrainFX->SetRTDimensions(newWidth, newHeight);
	terrainWaterFX->SetRTDimensions(newWidth, newHeight);

	pomFX->SetRTDimensions(newWidth, newHeight);

	reflectRefractFX->SetRTDimensions(newWidth, newHeight);
}

void ShaderManager::InitStandardEffects(ID3D11Device* device)
{
	try
	{
		texturedFullScreenQuadFX = new TexturedFullScreenQuadFX(device);
		debugDrawLightsFX = new DebugDrawLightsFX(device);
		skyDomeFX = new SkyDomeFX(device);

		tileForwardNormalMapFX = new TileForwardNormalMapFX(device);
		tileForwardNormalMapInstFX = new TileForwardNormalMapInstFX(device);
		tileForwardStandardFX = new TileForwardStandardFX(device);
		tileForwardTextureMapFX = new TileForwardTextureMapFX(device);
		tileForwardTextureMapInstFX = new TileForwardTextureMapInstFX(device);
		tileForwardDisplacementMappingFX = new TileForwardDisplacementMappingFX(device);
		tileForwardDisplacementMapInstFX = new TileForwardDisplacementMapInstFX(device);
		tileForwardSolidColourFX = new TileForwardSolidColourFX(device);
		tileForwardSolidColourInstFX = new TileForwardSolidColourInstFX(device);
		tileForwardAnimNormalMapFX = new TileForwardAnimNormalMapFX(device);
		tileForwardAnimTextureMapFX = new TileForwardAnimTextureMapFX(device);
		tileForwardAnimSolidColourFX = new TileForwardAnimSolidColourFX(device);
		
		oceanWaveFX = new OceanWaveFX(device);
		terrainFX = new TerrainFX(device); 
		terrainWaterFX = new TerrainWaterFX(device);

		pomFX = new ParallaxOcclusionMappingFX(device);

		//Roo's world specific
		reflectRefractFX = new ReflectRefractFX(device);

		//Post proc / screen space effects
		ssaoBlurFX = new SSAOBlurFX(device);
		ssaoMapFX = new SSAOMapFX(device);

		//Create others
		spriteFX = new SpriteFX(device);
	}
	catch (const std::bad_alloc&)
	{
		//Tells us when we allocate memory for the compiled shader incorrectly.
		OutputDebugStringW(L"Shader Manager Error - Bad Alloc (1) - Exiting\n");
		OutputDebugStringW(L"This is likely an error with your FX Directory\n");
		exit(-1);
	}
}

void ShaderManager::InitCSEffects(ID3D11Device* device)
{
	try
	{
		tileForwardLightCullCSFX = new TileForwardLightCullCSFX(device);
		ssaoBlurCSFX = new SSAOBlurCSFX(device);
	}
	catch (const std::bad_alloc&)
	{
		//Tells us when we allocate memory for the compiled shader incorrectly.
		OutputDebugStringW(L"Shader Manager Error - Bad Alloc (2) - Exiting\n");
		OutputDebugStringW(L"This is likely an error with your FX Directory\n");
		exit(-2);
	}
}